using System;
using System.Net;
using System.Net.Sockets;

namespace LiteNetLib.Ntp
{
	public sealed class NtpRequest : INetSocketListener
	{
		public const int DefaultPort = 123;

		private readonly NetSocket _socket;

		private readonly Action<NtpPacket> _onRequestComplete;

		private readonly IPEndPoint _ntpEndPoint;

		private NtpRequest(IPEndPoint endPoint, Action<NtpPacket> onRequestComplete)
		{
			_ntpEndPoint = endPoint;
			_onRequestComplete = onRequestComplete;
			_socket = new NetSocket(this);
			_socket.Bind(IPAddress.Any, IPAddress.IPv6Any, 0, false);
		}

		public static NtpRequest Create(IPEndPoint endPoint, Action<NtpPacket> onRequestComplete)
		{
			return new NtpRequest(endPoint, onRequestComplete);
		}

		public static NtpRequest Create(IPAddress ipAddress, Action<NtpPacket> onRequestComplete)
		{
			return Create(new IPEndPoint(ipAddress, 123), onRequestComplete);
		}

		public static NtpRequest Create(string ntpServerAddress, int port, Action<NtpPacket> onRequestComplete)
		{
			return Create(NetUtils.MakeEndPoint(ntpServerAddress, port), onRequestComplete);
		}

		public static NtpRequest Create(string ntpServerAddress, Action<NtpPacket> onRequestComplete)
		{
			return Create(NetUtils.MakeEndPoint(ntpServerAddress, 123), onRequestComplete);
		}

		public void Send()
		{
			SocketError errorCode = SocketError.Success;
			NtpPacket ntpPacket = new NtpPacket();
			ntpPacket.ValidateRequest();
			byte[] bytes = ntpPacket.Bytes;
			int num = _socket.SendTo(bytes, 0, bytes.Length, _ntpEndPoint, ref errorCode);
			if (errorCode != 0 || num != bytes.Length)
			{
				_onRequestComplete(null);
			}
		}

		public void Close()
		{
			_socket.Close();
		}

		void INetSocketListener.OnMessageReceived(byte[] data, int length, SocketError errorCode, IPEndPoint remoteEndPoint)
		{
			DateTime utcNow = DateTime.UtcNow;
			if (!remoteEndPoint.Equals(_ntpEndPoint))
			{
				return;
			}
			if (length < 48)
			{
				_onRequestComplete(null);
				return;
			}
			NtpPacket ntpPacket = NtpPacket.FromServerResponse(data, utcNow);
			try
			{
				ntpPacket.ValidateReply();
			}
			catch (InvalidOperationException)
			{
				ntpPacket = null;
			}
			_onRequestComplete(ntpPacket);
		}
	}
}
